import { getViewportSize, getOutputScale } from './render-util'
import { CSS_UNITS } from '../envelope/form/form'
class CanvasPool{
  constructor(){
    this.createableCount = 5
    this.canvas = []
    this.waitingHandles = []
  }

  async get(){
    let canvas = this.canvas.pop()
    if(canvas == null){ //等待归还
      if(this.createableCount > 0){
        this.createableCount--
        return document.createElement('canvas')
      } else {
        return this.waitingForStill()
      }
    }
    return canvas
  }

  async waitingForStill(){
    return new Promise((resolve, reject) => {
      this.waitingHandles.push(resolve)
    })
  }

  still(canvas){
    canvas.width = 0
    canvas.height = 0
    if(this.waitingHandles.length > 0){
      this.waitingHandles.shift()(canvas)
    } else {
      this.canvas.push(canvas)
    }
  }
}

const CANVAS_POLL = new CanvasPool()

const PAGE_RENDER_STATUS = {
    WAITING: 'WAITING', // 等待渲染
    RENDERING: 'RENDERING', // 加载中
    NEEDRERENDER: 'NEEDRERENDER', // 需要重新加载
    RERENDERING: 'RERENDERING', // 重新加载中
    RENDERED: 'RENDERED', // 加载完成
    ERROR: 'ERROR' // 渲染失败
}

class PageRender {
    constructor (docId, pageNumber, prePageProxy, pdfProxy, renderListener) {
        // 文档页数
       this.drawerType=false
        this.docId = docId
        this.page = pageNumber
        this.prePageProxy = prePageProxy
        this.pdfProxy = pdfProxy

        // PDFJS页面渲染带来
        this.pageProxy = null
        this.renderListener = renderListener

        // 渲染状态
        this.renderScale = 1 // 目前/之前渲染的比例
        this.renderStatus = PAGE_RENDER_STATUS.WAITING // 当前的渲染状态

        this.renderedImageData = null
        this.renderedWidth = 0
        this.renderedHeight = 0
    }

    setScale (scale) {
        if (this.renderScale === scale) return // 比例相同，不发生变化
        this.renderScale = scale

        // 等待中、出错、需要重新渲染不改变状态，重新启动
        if (this.renderStatus === PAGE_RENDER_STATUS.WAITING ||
            this.renderStatus === PAGE_RENDER_STATUS.ERROR ||
            this.renderStatus === PAGE_RENDER_STATUS.NEEDRERENDER) {
            return
        }

        // 正在渲染，重新渲染中， 需要停止渲染
        if (this.renderStatus === PAGE_RENDER_STATUS.RENDERING ||
            this.renderStatus === PAGE_RENDER_STATUS.RERENDERING) {
            this.renderStatus = PAGE_RENDER_STATUS.NEEDRERENDER
            this.cancelRender()
        }

        // 已经渲染完成 设置为带渲染
        if (this.renderStatus === PAGE_RENDER_STATUS.RENDERED) {
            this.renderStatus = PAGE_RENDER_STATUS.NEEDRERENDER
        }
    }

    async render (type) {
        // 已经渲染完成 渲染中 重新渲染中
        this.drawerType= type || false
        if (this.renderStatus === PAGE_RENDER_STATUS.RENDERED ||
            this.renderStatus === PAGE_RENDER_STATUS.RENDERING ||
            this.renderStatus === PAGE_RENDER_STATUS.RERENDERING) return

        // 进入渲染
        if (this.renderStatus === PAGE_RENDER_STATUS.ERROR ||
            this.renderStatus === PAGE_RENDER_STATUS.WAITING) {
            this.renderStatus = PAGE_RENDER_STATUS.RENDERING
        }

        // 将入重新渲染
        if (this.renderStatus === PAGE_RENDER_STATUS.NEEDRERENDER) {
            this.renderStatus = PAGE_RENDER_STATUS.RERENDERING
        }

        return this.doRender()
    }

    async doRender () {
        if (this.pageProxy) {
            return this.drawCanvas()
        } else {
            return this.pdfProxy.getPage(this.page).then(page => {
                this.pageProxy = page
                this.renderListener.onPageProxyLoadSuccess(this)
                return this.drawCanvas()
            }, err => {
                this.renderError()
                return Promise.reject(err)
            })
        }
    }

    async drawCanvas () {
        // const startDrawTime = Date.now()

        const pageProxy = this.pageProxy
        if (pageProxy === null) return this.renderError()

        const bcanvas = await CANVAS_POLL.get()
        const viewport = pageProxy.getViewport({ scale: this.renderScale * CSS_UNITS, offsetX: 100, offsetY: 100 })

        const size = getViewportSize(viewport)
        if(this.drawerType){
          bcanvas.style.width = '100%'
          bcanvas.style.height = '100%'
        }else {
          bcanvas.style.width = size.styleWidth + 'px'
          bcanvas.style.height = size.styleHeight + 'px'
        }
        bcanvas.width = size.width
        bcanvas.height = size.height
        const context = bcanvas.getContext('2d', { alpha: true })
        if (context == null) return this.renderError()
        const outputScale = getOutputScale(context)

        const transform = !outputScale.scaled ? null : [outputScale.sx, 0, 0, outputScale.sy, 0, 0]
        const renderContext = {
            canvasContext: context,
            viewport,
            enableWebGL: true,
            transform
        }

        if (this.renderTask) {
            this.renderTask.cancel()
            this.renderTask = null
        }
        const renderTask = pageProxy.render(renderContext)
        this.renderTask = renderTask

        return renderTask.promise.then(() => {
            this.renderTask = null
            this.renderStatus = PAGE_RENDER_STATUS.RENDERED

            bcanvas.toBlob(blob => {
              this.renderedImageData = URL.createObjectURL(blob)
              this.renderedWidth = size.styleWidth
              this.renderedHeight = size.styleHeight
              // console.info(`页面${this.page} 渲染耗时(canvas):${Date.now() - startDrawTime}ms`)
              this.renderListener.onPageRenderedSuccess(this)
            })
        }, reason => {
            if (/cancelled/.test(reason)) return // 需要重新渲染导致的取消
            this.renderError()
        }).then(() => {
          CANVAS_POLL.still(bcanvas)
        })
    }

    async cancelRender () {
        if (this.renderTask) {
            this.renderTask.cancel()
            this.renderTask = null
        }
    }

    renderError () {
        this.renderStatus = PAGE_RENDER_STATUS.ERROR
        this.renderListener.onPageRenderError(this)
    }

    getPageProxy () {
        return this.pageProxy || this.prePageProxy
    }

    getPageShowSize (scale = this.renderScale) {
        const size = getViewportSize(this.getPageProxy().getViewport({ scale: scale * CSS_UNITS }))
        return {
            width: size.styleWidth,
            height: size.styleHeight
        }
    }
}

export {
    PageRender,
    PAGE_RENDER_STATUS
}
